Previous slide Next slide Toggle fullscreen Open presenter view
Программирование сетевых приложений
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Содержание лекции
Архитектура «Модель-Представление-Контроллер» (MVC)
Создание графического интерфейса при помощи встроенных классов
Компоненты и контейнеры
Использование элементов управления, менеджеров компоновки и меню
Элементы управления
Основные понятия
Добавление и удаление элементов управления
Реагирование на элементы управления
Понятие менеджера компоновки
Работа с меню и диалоговыми окнами
Обработка событий
Модель делегирования событий
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
MVC в Qt
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Model/View Architecture
class MyModel : public QAbstractTableModel {
Q_OBJECT
private :
QList<QPair<QString, int >> data;
public :
int rowCount (const QModelIndex &parent = QModelIndex()) const override {
return data.size ();
}
int columnCount (const QModelIndex &parent = QModelIndex()) const override {
return 2 ;
}
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override {
if (!index.isValid () || role != Qt::DisplayRole)
return QVariant ();
if (index.column () == 0 )
return data[index.row ()].first;
else
return data[index.row ()].second;
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Создание базового GUI приложения
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
int main (int argc, char *argv[]) {
QApplication app (argc, argv) ;
QWidget window;
window.setWindowTitle ("Мое первое GUI приложение" );
window.resize (400 , 300 );
QLabel* label = new QLabel ("Привет, Qt!" );
QPushButton* button = new QPushButton ("Нажми меня" );
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget (label);
layout->addWidget (button);
window.setLayout (layout);
window.show ();
return app.exec ();
}
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Основные классы Qt GUI
Базовые классы окон
Класс
Назначение
QWidget
Базовый класс всех GUI элементов
QMainWindow
Главное окно приложения с меню и панелями инструментов
QDialog
Диалоговое окно для взаимодействия с пользователем
QFrame
Контейнер с рамкой
QScrollArea
Область с полосами прокрутки
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Компоненты и контейнеры
#include <QLineEdit>
#include <QTextEdit>
#include <QComboBox>
#include <QCheckBox>
#include <QRadioButton>
#include <QSlider>
#include <QProgressBar>
class WidgetsExample : public QWidget {
Q_OBJECT
public :
WidgetsExample (QWidget* parent = nullptr ) : QWidget (parent) {
QLineEdit* lineEdit = new QLineEdit (this );
lineEdit->setPlaceholderText ("Введите текст..." );
QTextEdit* textEdit = new QTextEdit (this );
textEdit->setPlainText ("Многострочный текст" );
QComboBox* comboBox = new QComboBox (this );
comboBox->addItems ({"Вариант 1" , "Вариант 2" , "Вариант 3" });
QCheckBox* checkBox = new QCheckBox ("Согласен" , this );
QRadioButton* radio1 = new QRadioButton ("Первый" , this );
QRadioButton* radio2 = new QRadioButton ("Второй" , this );
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Менеджеры компоновки (Layout Managers)
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QFormLayout>
#include <QStackedLayout>
class LayoutsExample : public QWidget {
Q_OBJECT
public :
LayoutsExample (QWidget* parent = nullptr ) : QWidget (parent) {
QHBoxLayout* hLayout = new QHBoxLayout;
hLayout->addWidget (new QPushButton ("Кнопка 1" ));
hLayout->addWidget (new QPushButton ("Кнопка 2" ));
hLayout->addStretch ();
QVBoxLayout* vLayout = new QVBoxLayout;
vLayout->addWidget (new QLabel ("Метка" ));
vLayout->addWidget (new QLineEdit);
vLayout->addSpacing (20 );
vLayout->addLayout (hLayout);
setLayout (vLayout);
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
GridLayout - табличная компоновка
#include <QGridLayout>
class GridLayoutExample : public QWidget {
Q_OBJECT
public :
GridLayoutExample (QWidget* parent = nullptr ) : QWidget (parent) {
QGridLayout* grid = new QGridLayout;
grid->addWidget (new QLabel ("Имя:" ), 0 , 0 );
grid->addWidget (new QLineEdit, 0 , 1 );
grid->addWidget (new QLabel ("Фамилия:" ), 1 , 0 );
grid->addWidget (new QLineEdit, 1 , 1 );
grid->addWidget (new QLabel ("Возраст:" ), 2 , 0 );
grid->addWidget (new QSpinBox, 2 , 1 );
QPushButton* okButton = new QPushButton ("OK" );
QPushButton* cancelButton = new QPushButton ("Отмена" );
grid->addWidget (okButton, 3 , 0 );
grid->addWidget (cancelButton, 3 , 1 );
grid->setHorizontalSpacing (10 );
grid->setVerticalSpacing (10 );
grid->setContentsMargins (20 , 20 , 20 , 20 );
setLayout (grid);
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
#include <QFormLayout>
class FormLayoutExample : public QWidget {
Q_OBJECT
public :
FormLayoutExample (QWidget* parent = nullptr ) : QWidget (parent) {
QFormLayout* formLayout = new QFormLayout;
QLineEdit* nameEdit = new QLineEdit;
QLineEdit* emailEdit = new QLineEdit;
QSpinBox* ageSpinBox = new QSpinBox;
QComboBox* countryCombo = new QComboBox;
countryCombo->addItems ({"Россия" , "Беларусь" , "Украина" , "Казахстан" });
formLayout->addRow ("Имя:" , nameEdit);
formLayout->addRow ("Email:" , emailEdit);
formLayout->addRow ("Возраст:" , ageSpinBox);
formLayout->addRow ("Страна:" , countryCombo);
QPushButton* submitButton = new QPushButton ("Отправить" );
QPushButton* resetButton = new QPushButton ("Сбросить" );
QHBoxLayout* buttonLayout = new QHBoxLayout;
buttonLayout->addWidget (submitButton);
buttonLayout->addWidget (resetButton);
formLayout->addRow (buttonLayout);
setLayout (formLayout);
setWindowTitle ("Форма регистрации" );
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Работа с меню
#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QStatusBar>
class MainWindow : public QMainWindow {
Q_OBJECT
public :
MainWindow (QWidget* parent = nullptr ) : QMainWindow (parent) {
createMenuBar ();
createStatusBar ();
setWindowTitle ("Приложение с меню" );
resize (800 , 600 );
}
private :
void createMenuBar () {
QMenu* fileMenu = menuBar ()->addMenu ("Файл" );
QAction* newAction = new QAction ("Новый" , this );
newAction->setShortcut (QKeySequence::New);
newAction->setStatusTip ("Создать новый файл" );
QAction* openAction = new QAction ("Открыть..." , this );
openAction->setShortcut (QKeySequence::Open);
QAction* saveAction = new QAction ("Сохранить" , this );
saveAction->setShortcut (QKeySequence::Save);
QAction* exitAction = new QAction ("Выход" , this );
exitAction->setShortcut (QKeySequence::Quit);
fileMenu->addAction (newAction);
fileMenu->addAction (openAction);
fileMenu->addAction (saveAction);
fileMenu->addSeparator ();
fileMenu->addAction (exitAction);
connect (exitAction, &QAction::triggered, this , &QMainWindow::close);
}
void createStatusBar () {
statusBar ()->showMessage ("Готово" );
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Панели инструментов и панели состояния
#include <QToolBar>
#include <QStatusBar>
#include <QIcon>
class ToolbarExample : public QMainWindow {
Q_OBJECT
public :
ToolbarExample (QWidget* parent = nullptr ) : QMainWindow (parent) {
QToolBar* fileToolbar = addToolBar ("Файл" );
QAction* newAction = new QAction (QIcon (":/icons/new.png" ), "Новый" , this );
QAction* openAction = new QAction (QIcon (":/icons/open.png" ), "Открыть" , this );
QAction* saveAction = new QAction (QIcon (":/icons/save.png" ), "Сохранить" , this );
fileToolbar->addAction (newAction);
fileToolbar->addAction (openAction);
fileToolbar->addAction (saveAction);
fileToolbar->addSeparator ();
QToolButton* toolButton = new QToolButton (this );
toolButton->setText ("Инструменты" );
toolButton->setPopupMode (QToolButton::MenuButtonPopup);
QMenu* toolMenu = new QMenu (this );
toolMenu->addAction ("Инструмент 1" );
toolMenu->addAction ("Инструмент 2" );
toolButton->setMenu (toolMenu);
fileToolbar->addWidget (toolButton);
statusBar ()->showMessage ("Приложение запущено" );
QLabel* permanentLabel = new QLabel ("Готов" );
statusBar ()->addPermanentWidget (permanentLabel);
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Диалоговые окна
#include <QMessageBox>
#include <QFileDialog>
#include <QInputDialog>
#include <QColorDialog>
#include <QFontDialog>
class DialogsExample : public QWidget {
Q_OBJECT
public slots:
void showMessageBox () {
QMessageBox::information (this , "Информация" ,
"Операция выполнена успешно!" );
int reply = QMessageBox::question (this , "Подтверждение" ,
"Вы уверены, что хотите удалить?" ,
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
}
}
void showFileDialog () {
QString fileName = QFileDialog::getOpenFileName (
this ,
"Открыть файл" ,
"" ,
"Текстовые файлы (*.txt);;Все файлы (*.*)"
);
if (!fileName.isEmpty ()) {
}
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Пользовательские диалоговые окна
#include <QDialog>
#include <QDialogButtonBox>
class CustomDialog : public QDialog {
Q_OBJECT
private :
QLineEdit* nameEdit;
QSpinBox* ageSpinBox;
QCheckBox* agreeCheckBox;
public :
CustomDialog (QWidget* parent = nullptr ) : QDialog (parent) {
setWindowTitle ("Пользовательский диалог" );
setModal (true );
resize (300 , 200 );
nameEdit = new QLineEdit;
ageSpinBox = new QSpinBox;
ageSpinBox->setRange (1 , 120 );
agreeCheckBox = new QCheckBox ("Я согласен с условиями" );
QDialogButtonBox* buttonBox = new QDialogButtonBox (
QDialogButtonBox::Ok | QDialogButtonBox::Cancel
);
connect (buttonBox, &QDialogButtonBox::accepted, this , &QDialog::accept);
connect (buttonBox, &QDialogButtonBox::rejected, this , &QDialog::reject);
QFormLayout* layout = new QFormLayout;
layout->addRow ("Имя:" , nameEdit);
layout->addRow ("Возраст:" , ageSpinBox);
layout->addRow (agreeCheckBox);
layout->addRow (buttonBox);
setLayout (layout);
}
QString getName () const { return nameEdit->text (); }
int getAge () const { return ageSpinBox->value (); }
bool isAgreed () const { return agreeCheckBox->isChecked (); }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Обработка событий - Сигналы и слоты
#include <QObject>
#include <QDebug>
class EventHandler : public QObject {
Q_OBJECT
public slots:
void handleButtonClicked () {
qDebug () << "Кнопка нажата!" ;
}
void handleTextChanged (const QString& text) {
qDebug () << "Текст изменен:" << text;
}
void handleValueChanged (int value) {
qDebug () << "Значение изменено:" << value;
}
};
class WidgetExample : public QWidget {
Q_OBJECT
public :
WidgetExample (QWidget* parent = nullptr ) : QWidget (parent) {
QPushButton* button = new QPushButton ("Нажми меня" , this );
QLineEdit* lineEdit = new QLineEdit (this );
QSlider* slider = new QSlider (Qt::Horizontal, this );
EventHandler* handler = new EventHandler (this );
connect (button, &QPushButton::clicked,
handler, &EventHandler::handleButtonClicked);
connect (lineEdit, &QLineEdit::textChanged,
handler, &EventHandler::handleTextChanged);
connect (slider, &QSlider::valueChanged,
handler, &EventHandler::handleValueChanged);
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Пользовательские события
#include <QEvent>
#include <QMouseEvent>
#include <QKeyEvent>
class CustomWidget : public QWidget {
Q_OBJECT
protected :
void mousePressEvent (QMouseEvent* event) override {
if (event->button () == Qt::LeftButton) {
qDebug () << "Левая кнопка мыши нажата в точке:"
<< event->pos ();
}
}
void mouseMoveEvent (QMouseEvent* event) override {
qDebug () << "Мышь перемещена в точку:" << event->pos ();
}
void mouseReleaseEvent (QMouseEvent* event) override {
qDebug () << "Кнопка мыши отпущена" ;
}
void keyPressEvent (QKeyEvent* event) override {
qDebug () << "Клавиша нажата:" << event->key ()
<< "Текст:" << event->text ();
if (event->key () == Qt::Key_Escape) {
close ();
}
}
void keyReleaseEvent (QKeyEvent* event) override {
qDebug () << "Клавиша отпущена:" << event->key ();
}
void resizeEvent (QResizeEvent* event) override {
qDebug () << "Размер изменен с" << event->oldSize ()
<< "на" << event->size ();
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Фильтры событий
#include <QEvent>
#include <QObject>
class EventFilter : public QObject {
Q_OBJECT
protected :
bool eventFilter (QObject* obj, QEvent* event) override {
if (event->type () == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast <QKeyEvent*>(event);
qDebug () << "Фильтр: нажата клавиша" << keyEvent->key ()
<< "в объекте" << obj->objectName ();
if (keyEvent->key () == Qt::Key_Return) {
return true ;
}
}
return QObject::eventFilter (obj, event);
}
};
class FilterExample : public QWidget {
Q_OBJECT
public :
FilterExample (QWidget* parent = nullptr ) : QWidget (parent) {
QLineEdit* lineEdit1 = new QLineEdit (this );
QLineEdit* lineEdit2 = new QLineEdit (this );
lineEdit1->setObjectName ("lineEdit1" );
lineEdit2->setObjectName ("lineEdit2" );
EventFilter* filter = new EventFilter (this );
lineEdit1->installEventFilter (filter);
lineEdit2->installEventFilter (filter);
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Пользовательские события и сигналы
#include <QEvent>
#include <QCoreApplication>
const QEvent::Type CustomEventType = static_cast <QEvent::Type>(QEvent::User + 1 );
class CustomEvent : public QEvent {
private :
QString message;
int priority;
public :
CustomEvent (const QString& msg, int prio)
: QEvent (CustomEventType), message (msg), priority (prio) {}
QString getMessage () const { return message; }
int getPriority () const { return priority; }
};
class CustomEventWidget : public QWidget {
Q_OBJECT
signals:
void customSignal (const QString& message, int value) ;
public :
CustomEventWidget (QWidget* parent = nullptr ) : QWidget (parent) {}
void sendCustomEvent (const QString& message, int priority) {
CustomEvent* event = new CustomEvent (message, priority);
QCoreApplication::postEvent (this , event);
}
protected :
void customEvent (QEvent* event) override {
if (event->type () == CustomEventType) {
CustomEvent* customEvent = static_cast <CustomEvent*>(event);
qDebug () << "Пользовательское событие:"
<< customEvent->getMessage ()
<< "Приоритет:" << customEvent->getPriority ();
emit customSignal (customEvent->getMessage(),
customEvent->getPriority()) ;
}
}
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Современные подходы к GUI разработке
QML и Qt Quick
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main (int argc, char *argv[]) {
QGuiApplication app (argc, argv) ;
QQmlApplicationEngine engine;
engine.load (QUrl (QStringLiteral ("qrc:/main.qml" )));
if (engine.rootObjects ().isEmpty ())
return -1 ;
return app.exec ();
}
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
QML разметка (main.qml)
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
id: window
visible : true
width : 640
height : 480
title : qsTr("Современный GUI на QML" )
Rectangle {
anchors.fill : parent
gradient : Gradient {
GradientStop { position : 0.0 ; color : "#1e3c72" }
GradientStop { position : 1.0 ; color : "#2a5298" }
}
Column {
anchors.centerIn : parent
spacing : 20
Text {
text : qsTr("Добро пожаловать в Qt Quick!" )
font.pixelSize : 24
color : "white"
anchors.horizontalCenter : parent .horizontalCenter
}
Button {
text : qsTr("Нажми меня" )
anchors.horizontalCenter : parent .horizontalCenter
onClicked : {
console .log("Кнопка нажата!" )
}
}
}
}
}
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Лучшие практики GUI разработки
1. Архитектурные принципы
Разделение ответственности - используйте MVC/MVP
Минимизация зависимостей - слабая связанность компонентов
Повторное использование - создавайте переиспользуемые компоненты
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
2. Производительность
void updateMultipleWidgets () {
setUpdatesEnabled (false );
label1->setText ("Новый текст 1" );
label2->setText ("Новый текст 2" );
progressBar->setValue (50 );
setUpdatesEnabled (true );
}
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
3. Пользовательский опыт
Отзывчивый интерфейс - используйте потоки для длительных операций
Интуитивность - следуйте стандартам интерфейса
Доступность - учитывайте пользователей с ограниченными возможностями
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Резюме
Ключевые концепции
Архитектура MVC - основа организации GUI приложений
Сигналы и слоты - механизм взаимодействия компонентов
Менеджеры компоновки - автоматическое размещение элементов
Обработка событий - реакция на действия пользователя
Диалоговые окна - взаимодействие с пользователем
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Инструменты Qt для GUI
QWidget - базовый класс всех элементов интерфейса
QLayout - система компоновки
QMainWindow - главное окно приложения
QDialog - диалоговые окна
Сигналы и слоты - механизм обработки событий
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Дальнейшее изучение
QML и Qt Quick - современные технологии GUI
Анимации и переходы - улучшение пользовательского опыта
Кастомные виджеты - создание уникальных компонентов
Интернационализация - поддержка многоязычности
Тестирование GUI - автоматизированное тестирование интерфейса
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений
Вопросы для самопроверки
Что такое архитектура MVC и как она реализована в Qt?
Какие существуют типы менеджеров компоновки и когда их использовать?
Как подключить обработчик события к кнопке?
Чем отличается QMainWindow от QDialog?
Как создать пользовательское событие и обработать его?
Какие существуют стандартные диалоговые окна в Qt?
Как реализовать фильтрацию событий?
Что такое сигналы и слоты в Qt?
Как создать меню и панель инструментов?
Какие лучшие практики следует учитывать при разработке GUI?
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Заметки докладчика:
- GUI — обязательная часть клиентских сетевых приложений (мессенджеры, почтовые клиенты, FTP-клиенты и т.д.)
- В данной лекции рассматривается подход Qt Widgets (классический, на C++)
- Qt Quick/QML представлен кратко как современная альтернатива — декларативный язык для описания UI
- Лабораторная работа: создать GUI для мессенджера — прямая связь с лекцией 11 (RPC, удалённые вызовы)
- Для сетевых приложений критически важно: GUI не должен блокировать сетевые операции (используем потоки и асинхронные сигналы/слоты)
Заметки докладчика:
- Каждый Qt GUI-приложение должен иметь ровно один объект QApplication (или QGuiApplication для QML)
- QWidget — базовый класс для всех визуальных элементов (кнопки, метки, окна — всё наследуется от QWidget)
- Способы создания UI в Qt: 1) программно (наш подход в лекции), 2) в Qt Designer (.ui файлы, конвертируемые в код), 3) в QML (декларативно)
- app.exec() запускает главный цикл обработки событий (event loop) — это блокирующий вызов
- Для сетевых приложений: QApplication также обрабатывает события от сокетов через event loop (QSocketNotifier)
Заметки докладчика:
- НИКОГДА не используйте абсолютное позиционирование (setGeometry, move) в реальных проектах — элементы «сломаются» при изменении размера окна
- Менеджеры компоновки автоматически обрабатывают изменение размеров, разные разрешения экрана, локализацию (разную длину текста)
- QVBoxLayout — вертикальный стек (виджеты сверху вниз), QHBoxLayout — горизонтальный ряд (слева направо), QGridLayout — табличная сетка
- Компоновки можно вкладывать друг в друга для создания сложных интерфейсов (например, QHBoxLayout внутри QVBoxLayout)
- addStretch() добавляет «пружину» — растяжимое пустое пространство
Заметки докладчика:
- Сигналы и слоты — механизм Qt для обработки событий (альтернатива колбэкам/слушателям в других фреймворках)
- Ключевое преимущество: типобезопасность (проверка на этапе компиляции), работа между потоками (queued connection)
- Новый синтаксис: connect(sender, &Sender::signal, receiver, &Receiver::slot) — предпочтительный
- Для сетевых приложений: сигнал readyRead() сокета подключается к слоту обработки данных — это основа асинхронного сетевого ввода-вывода в Qt
- Сигнал может быть подключён к нескольким слотам, слот — к нескольким сигналам
- Lambda-функции можно использовать как слоты: connect(button, &QPushButton::clicked, [](){ ... });
Заметки докладчика:
- В Qt события доставляются через метод QObject::event() — это точка входа для всех событий
- Для стандартных событий переопределяйте конкретные обработчики: mousePressEvent, keyPressEvent, resizeEvent и т.д.
- Для нестандартных событий переопределяйте event() и проверяйте тип через event->type()
- Фильтры событий (eventFilter) позволяют перехватывать события других объектов — полезно для валидации ввода
- Для сетевых приложений: QNetworkAccessManager генерирует сигналы (finished(), readyRead()), а не события мыши/клавиатуры — это другой механизм взаимодействия
Заметки докладчика:
- QML — декларативный язык (синтаксис, похожий на JSON) для описания UI
- Отделяет дизайн интерфейса от логики на C++ — дизайнер может работать в Qt Design Studio
- Подходит для быстрого прототипирования и мобильных/встроенных приложений
- Взаимодействие C++ и QML через Q_PROPERTY и зарегистрированные типы (qmlRegisterType)
- Для данного курса QML не является обязательным, но полезно знать о его существовании как альтернативе
- Qt Quick использует GPU-ускоренный рендеринг (Scene Graph) — лучше для анимаций
Заметки докладчика:
Ожидаемые ответы на вопросы самопроверки:
1. MVC разделяет данные (Model), отображение (View) и логику (Controller). В Qt — Model/View/Delegate (MVD): QAbstractItemModel + QListView + QStyledItemDelegate.
2. QVBoxLayout (вертикальный стек), QHBoxLayout (горизонтальный ряд), QGridLayout (таблица), QFormLayout (форма «метка — поле»), QStackedLayout (переключаемые страницы). QVBoxLayout/HLayout — для простых случаев, QGridLayout — для табличных данных, QFormLayout — для форм ввода.
3. Через механизм сигналов и слотов: connect(button, &QPushButton::clicked, this, &MyClass::onClicked). Также можно подключить к лямбде: connect(button, &QPushButton::clicked, [](){ ... }).
4. QMainWindow — главное окно приложения с меню, панелями инструментов и статус-баром. QDialog — модальное/немодальное диалоговое окно для взаимодействия с пользователем (ввод данных, подтверждения).
5. Определить тип события (QEvent::User + N), создать класс-наследник QEvent, отправить через QCoreApplication::postEvent(), обработать в customEvent().
6. QMessageBox (информация, предупреждение, вопрос), QFileDialog (открытие/сохранение файлов), QInputDialog (ввод текста/числа), QColorDialog (выбор цвета), QFontDialog (выбор шрифта).
7. Наследовать QObject, переопределить eventFilter(), вызвать installEventFilter() на целевом объекте. Возвращать true — событие перехвачено, false — передать дальше.
8. Сигнал — объявление события (signals:), слот — обработчик (public slots:/private slots:). Связываются через connect(). Работают между потоками (queued connection). Типобезопасны.
9. Через QMenuBar: menuBar()->addMenu("Файл"), добавить QAction с помощью addAction(). Панель инструментов: addToolBar("Имя"), addAction() на панель. QAction может быть общим для меню и панели инструментов.
10. Использовать менеджеры компоновки (не абсолютное позиционирование), разделять логику и UI (MVC), не блокировать GUI-поток (длительные операции в отдельных потоках), использовать setUpdatesEnabled для групповых обновлений, соблюдать стандарты платформы.